import utime as time
import ujson as json
import urequests as requests
# 移除以下行 ▼
from machine import I2S, Pin
import sys
import ubinascii  
import _thread
from setcfg import DAT


# 修改音频参数配置
CHUNK = 1024
ASR_SERVER_URL =  DAT["asr"]["url"]
RATE = 16000
try:
    # 修改后的I2S初始化配置
    i2s = I2S(
        0,
        sck=Pin(DAT["asr"]["sck"]),
        ws=Pin(DAT["asr"]["ws"]),
        sd=Pin(DAT["asr"]["sd"]),
        mode=I2S.RX,
        bits=16,
        format=I2S.MONO,  # 仅保留单声道配置
        rate=16000,
        ibuf=CHUNK*4
    )
except Exception as e:
    print("Error initializing I2S:", e)
    i2s = None

def bytes_to_int16(audio_data):
    """将字节数组转换为int16有符号整数列表（小端序）"""
    samples = []
    for i in range(0, len(audio_data), 2):
        b1 = audio_data[i]
        b2 = audio_data[i+1]
        val = (b2 << 8) | b1
        if val >= 0x8000:
            val -= 0x10000
        samples.append(val)
    return samples
def calculate_rms(audio_data):
    """计算标准的均方根值 (RMS)"""
    if not audio_data:
        return 0
    sum_squares = sum(s ** 2 for s in audio_data)
    mean_square = sum_squares / len(audio_data)
    return mean_square ** 0.5

def calibrate_noise_once():
    if i2s is None:
        print("I2S未初始化")
        return
    global ENERGY_THRESHOLD, CALIBRATION_DONE, last_calibration_time
    if CALIBRATION_DONE:
        return    
    print("正在进行环境噪声校准...")
    time.sleep(2)
    duration = 2  # 缩短校准时间
    rms_values = []
    
    # 新的采样逻辑：仅采集最低的30%样本
    total_samples = int(duration * RATE / CHUNK)
    print(f"共需采样 {total_samples} 次...")  # 新增样本总数显示
    
    for i in range(total_samples):
        # 新增进度显示（每10%更新一次）
        if i % (total_samples // 10 + 1) == 0:
            print(f"\r采样进度: [{i+1}/{total_samples}] {(i+1)*100/total_samples:.0f}%", end='')
            
        audio_data = bytearray(CHUNK)
        countsize = i2s.readinto(audio_data)
        
        # 修改样本转换方式 ▼
        samples = bytes_to_int16(audio_data)  # 原始数据
        rms = calculate_rms(samples)  # 放大计算已集成到RMS函数
        #print(f"[校准采样{i}] RMS: {rms:.2f}")  # 新增实时打印
        # 修改后的动态过滤逻辑 ▼
        if len(rms_values) >= 5:  # 至少有5个样本后再开始过滤
            moving_avg = sum(rms_values[-5:])/5  # 计算最近5个样本的移动平均
            if rms > 3.0 * moving_avg:  # 从2.5调整为4.0倍
                print(f"过滤异常值: {rms:.1f} > {4.0*moving_avg:.1f}")
                continue
        
        rms_values.append(rms)
    
    print("\n")  # 换行保证后续输出格式
    # 使用最低的30%样本计算基准噪声
    # 修改采样逻辑为动态窗口调整 ▼
    # 调整噪声基准计算参数 ▼
    sorted_rms = sorted(rms_values,reverse=True)[:int(len(rms_values)*0.3)]  # 40%→25%
    print(sorted_rms);
    base_noise = sum(sorted_rms)/len(sorted_rms) if sorted_rms else 0
    ENERGY_THRESHOLD = base_noise * 8.0  # 3.0→5.0
    print(f"环境噪声基准: {base_noise:.2f}，激活阈值: {ENERGY_THRESHOLD:.2f}")
    CALIBRATION_DONE = True
    # 修改最终输出提示
    print(f"\n[校准完成] 环境噪声基准: {base_noise:.2f}，当前阈值: {ENERGY_THRESHOLD:.2f}")
    last_calibration_time = time.time()  # 重置校准时间戳

# 修改录音函数中的数据处理部分
# 在全局状态声明之后添加新函数
ENERGY_THRESHOLD = None
CALIBRATION_DONE = False

from tts_module_m import is_play
# 补全record_audio函数
def record_audio():
    if i2s is None:
        print("I2S未初始化")
        return None
     
    global ENERGY_THRESHOLD, CALIBRATION_DONE
    if not CALIBRATION_DONE:
        raise RuntimeError("请先执行手动校准")
        
    SILENCE_LIMIT = 1
    PRE_BUFFER_SECONDS = 0.5
    frames = []
    pre_buffer = []
    last_sound_time = time.time()
    is_recording = False

    print(f"等待声音输入 (阈值: {ENERGY_THRESHOLD:.2f})...")
    read_count = 0  # 新增计数器
    while True:
        if is_play==1:
            time.sleep(0.1)
            break
        audio_data = bytearray(CHUNK)
        i2s.readinto(audio_data)

        read_count += 1
        
        # 修改样本转换方式 ▼
        samples = bytes_to_int16(audio_data)  # 统一使用转换函数
        
        current_rms = calculate_rms(samples)
        #print(f"[实时检测] RMS: {current_rms:.2f}")  # 新增实时打印
        
        # 修改阈值判断逻辑，添加滞后系数
        HYSTERESIS_THRESHOLD = ENERGY_THRESHOLD * 0.8 if is_recording else ENERGY_THRESHOLD
        # 修改阈值判断逻辑，增加最小录音时长限制 ▼
        if current_rms > HYSTERESIS_THRESHOLD :
            if not is_recording:
                print(f"\n[触发] 当前RMS:{current_rms:.1f} 阈值:{HYSTERESIS_THRESHOLD:.1f} (基准阈值:{ENERGY_THRESHOLD:.1f})")
                print("开始录音...")
                is_recording = True
                frames.extend(pre_buffer[-int(PRE_BUFFER_SECONDS*RATE/CHUNK):])
                start_time = time.time()  # 记录录音开始时间
            last_sound_time = time.time()
            #print(f"\n[触发] 当前RMS:{current_rms:.1f} 阈值:{HYSTERESIS_THRESHOLD:.1f} (基准阈值:{ENERGY_THRESHOLD:.1f})")

        
        # 增强版静音检测 ▼
        if is_recording:
            # 条件1：必须至少录音0.5秒
            # 条件2：静音超时1秒
            silent_ok = (time.time() - start_time > 0.5) 
            timeout_ok = (time.time() - last_sound_time > SILENCE_LIMIT)            
            if silent_ok and timeout_ok:
                duration = time.time() - start_time
                print(f"\n达到停止条件（已录音{duration:.1f}s，静音{SILENCE_LIMIT}s）")
                break

        # 将静音检测移到主循环中 ▼
        if is_recording:
            silent_duration = time.time() - last_sound_time
            if silent_duration > SILENCE_LIMIT:
                print(f"\n检测到持续静音{silent_duration:.1f}秒，停止录音")
                break

        # 移除原break判断，改为实时检测
        if is_recording :            
            frames.append(audio_data)
            # 显示录音时长
            print(f"\r录音时长: {time.time() - last_sound_time + SILENCE_LIMIT:.1f}s", end='')
        else:
            pre_buffer.append(audio_data)
            if len(pre_buffer) > PRE_BUFFER_SECONDS * RATE / CHUNK:
                pre_buffer.pop(0)
    if is_play==0:
        wav_header = generate_wav_header(len(frames)*CHUNK)
        return wav_header + b''.join(frames)
    else:
        time.sleep(0.1)
        return None



# 补充服务器通信函数（确认函数定义前无多余缩进）
def send_audio_to_server(audio_data):
    if audio_data is None:       
        return
    
    data = {
        # 保持字典值对齐
        "audio": ubinascii.b2a_base64(audio_data).decode('utf-8').strip(),
        "audio_format": "wav",
        "sample_rate": RATE,
        "lang": "zh_cn",
        "punc": 1
    }

    try:
        response = requests.post(ASR_SERVER_URL, 
                              data=json.dumps(data),
                              headers={'Content-Type': 'application/json'})
        return response.json().get("result", {}).get("transcription", "")
    except Exception as e:
        print("请求失败:", e)
        return None
# 生成WAV头生成函数
def generate_wav_header(data_size):
    return bytes(
        b'RIFF' +
        (data_size + 36).to_bytes(4, 'little') +
        b'WAVEfmt ' +
        (16).to_bytes(4, 'little') +  # fmt chunk size
        (1).to_bytes(2, 'little') +   # PCM格式
        (1).to_bytes(2, 'little') +   # 单声道
        (16000).to_bytes(4, 'little') +  # 采样率
        (16000 * 1 * 2).to_bytes(4, 'little') +  # 字节率
        (2).to_bytes(2, 'little') +    # 块对齐
        (16).to_bytes(2, 'little') +   # 位深
        b'data' +
        data_size.to_bytes(4, 'little')
    )

def start_asr():    
    if i2s is None:
        print("I2S未初始化")
        return
    from angencmd import call_ai_api
    calibrate_noise_once()
    def ars_ser():
        
        try:           
           while True:
             try:
                audio_data = record_audio()
                if is_play==1:
                    continue
                transcription = send_audio_to_server(audio_data)             
                if transcription is not None:                              
                    call_ai_api(transcription)                    
             except Exception as e:
                print(f"while 调用失败: {e}")            
        except Exception as e:
            print(f"asr error:{e}")
    
    _thread.start_new_thread(ars_ser, ())

#     calibrate_noise_once()
#     while True:
#         audio_data = record_audio()
#         transcription = send_audio_to_server(audio_data)
#         print(f"\n识别结果: {transcription}")
# except Exception as e:
#     print("发生错误:", e)
    

# 新增全样本测试函数
# 在文件顶部附近添加转换函数 ▼

# def test_3seconds():
#     import usocket as socket
#     print("\n=== 持续音频数据发送 ===")

#     # 创建UDP套接字
#     sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
#     server_address = ('192.168.4.2', 9999)

#     try:
#         while True:
#             audio_data = bytearray(CHUNK * 4)
#             i2s.readinto(audio_data)
            
#             # 调用独立转换函数 ▼
#             raw_samples = bytes_to_int16(audio_data)
            
#             raw_max = max(raw_samples)
#             raw_min = min(raw_samples)
            
#             # 计算绝对值范围
#             samples = [abs(val) & 0x7FFF for val in raw_samples]  # 在此处统一计算
#             min_val = min(samples)
#             max_val = max(samples)
            
#             # 发送音频数据到UDP服务器
#             sock.sendto(audio_data, server_address)
            
#             # 修正后的打印语句（统一使用已计算的变量）
#             print(f"\r原始[{raw_min}~{raw_max}] 绝对值[{min_val}~{max_val}] | 已发送:{len(audio_data)}字节        ", end='')
            
#             time.sleep(0.01)
            
#     except KeyboardInterrupt:
#         print("\n用户中断，停止发送")
#     finally:
#         sock.close()

#     print("\n噪声值分布:")
#     for value in sorted(hist):
#         print(f"{value}: {hist[value]}次")
#     print(f"总采样数: {sum(hist.values())}")
# # 主程序入口
# try:
#     print("系统初始化完成")
#     test_3seconds()  # 核心测试函数
#     print("\n测试完成，退出程序")
#     sys.exit(0)
    
# except Exception as e:
#     print(f"运行错误: {e}")
# finally:
#     i2s.deinit()
